const isWeex = typeof WXEnvironment !== 'undefined'
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform)
const isWeexAndroid = isWeex && !isWeexIOS

import GLmethod from '../context-webgl/GLmethod'

const GCanvasModule =
    typeof weex !== 'undefined' && weex.requireModule
        ? weex.requireModule('gcanvas')
        : typeof __weex_require__ !== 'undefined'
        ? __weex_require__('@weex-module/gcanvas')
        : {}

let isDebugging = false

let isComboDisabled = false

const logCommand = (function () {
    const methodQuery = []
    Object.keys(GLmethod).forEach((key) => {
        methodQuery[GLmethod[key]] = key
    })
    const queryMethod = (id) => {
        return methodQuery[parseInt(id)] || 'NotFoundMethod'
    }
    const logCommand = (id, cmds) => {
        const mId = cmds.split(',')[0]
        const mName = queryMethod(mId)
        console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`)
    }
    return logCommand
})()

function joinArray(arr, sep) {
    let res = ''
    for (let i = 0; i < arr.length; i++) {
        if (i !== 0) {
            res += sep
        }
        res += arr[i]
    }
    return res
}

const commandsCache = {}

const GBridge = {
    callEnable: (ref, configArray) => {
        commandsCache[ref] = []

        return GCanvasModule.enable({
            componentId: ref,
            config: configArray,
        })
    },

    callEnableDebug: () => {
        isDebugging = true
    },

    callEnableDisableCombo: () => {
        isComboDisabled = true
    },

    callSetContextType: function (componentId, context_type) {
        GCanvasModule.setContextType(context_type, componentId)
    },

    callReset: function (id) {
        GCanvasModule.resetComponent && canvasModule.resetComponent(componentId)
    },

    render: isWeexIOS
        ? function (componentId) {
              return GCanvasModule.extendCallNative({
                  contextId: componentId,
                  type: 0x60000001,
              })
          }
        : function (componentId) {
              return callGCanvasLinkNative(componentId, 0x60000001, 'render')
          },

    render2d: isWeexIOS
        ? function (componentId, commands, callback) {
              if (isDebugging) {
                  console.log('>>> >>> render2d ===')
                  console.log('>>> commands: ' + commands)
              }

              GCanvasModule.render([commands, callback ? true : false], componentId, callback)
          }
        : function (componentId, commands, callback) {
              if (isDebugging) {
                  console.log('>>> >>> render2d ===')
                  console.log('>>> commands: ' + commands)
              }

              callGCanvasLinkNative(componentId, 0x20000001, commands)
              if (callback) {
                  callback()
              }
          },

    callExtendCallNative: isWeexIOS
        ? function (componentId, cmdArgs) {
              throw 'should not be here anymore ' + cmdArgs
          }
        : function (componentId, cmdArgs) {
              throw 'should not be here anymore ' + cmdArgs
          },

    flushNative: isWeexIOS
        ? function (componentId) {
              const cmdArgs = joinArray(commandsCache[componentId], ';')
              commandsCache[componentId] = []

              if (isDebugging) {
                  console.log('>>> >>> flush native ===')
                  console.log('>>> commands: ' + cmdArgs)
              }

              const result = GCanvasModule.extendCallNative({
                  contextId: componentId,
                  type: 0x60000000,
                  args: cmdArgs,
              })

              const res = result && result.result

              if (isDebugging) {
                  console.log('>>> result: ' + res)
              }

              return res
          }
        : function (componentId) {
              const cmdArgs = joinArray(commandsCache[componentId], ';')
              commandsCache[componentId] = []

              if (isDebugging) {
                  console.log('>>> >>> flush native ===')
                  console.log('>>> commands: ' + cmdArgs)
              }

              const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs)

              if (isDebugging) {
                  console.log('>>> result: ' + result)
              }

              return result
          },

    callNative: function (componentId, cmdArgs, cache) {
        if (isDebugging) {
            logCommand(componentId, cmdArgs)
        }

        commandsCache[componentId].push(cmdArgs)

        if (!cache || isComboDisabled) {
            return GBridge.flushNative(componentId)
        } else {
            return undefined
        }
    },

    texImage2D(componentId, ...args) {
        if (isWeexIOS) {
            if (args.length === 6) {
                const [target, level, internalformat, format, type, image] = args
                GBridge.callNative(
                    componentId,
                    GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src,
                )
            } else if (args.length === 9) {
                const [target, level, internalformat, width, height, border, format, type, image] = args
                GBridge.callNative(
                    componentId,
                    GLmethod.texImage2D +
                        ',' +
                        9 +
                        ',' +
                        target +
                        ',' +
                        level +
                        ',' +
                        internalformat +
                        ',' +
                        width +
                        ',' +
                        height +
                        ',' +
                        border +
                        ',' +
                        +format +
                        ',' +
                        type +
                        ',' +
                        (image ? image.src : 0),
                )
            }
        } else if (isWeexAndroid) {
            if (args.length === 6) {
                const [target, level, internalformat, format, type, image] = args
                GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src)
            } else if (args.length === 9) {
                const [target, level, internalformat, width, height, border, format, type, image] = args
                GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, image ? image.src : 0)
            }
        }
    },

    texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
        if (isWeexIOS) {
            if (arguments.length === 8) {
                GBridge.callNative(
                    componentId,
                    GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset,
                    +',' + format + ',' + type + ',' + image.src,
                )
            }
        } else if (isWeexAndroid) {
            GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src)
        }
    },

    bindImageTexture(componentId, src, imageId) {
        GCanvasModule.bindImageTexture([src, imageId], componentId)
    },

    perloadImage([url, id], callback) {
        GCanvasModule.preLoadImage([url, id], function (image) {
            image.url = url
            image.id = id
            callback(image)
        })
    },

    measureText(text, fontStyle, componentId) {
        return GCanvasModule.measureText([text, fontStyle], componentId)
    },

    getImageData(componentId, x, y, w, h, callback) {
        GCanvasModule.getImageData([x, y, w, h], componentId, callback)
    },

    putImageData(componentId, data, x, y, w, h, callback) {
        GCanvasModule.putImageData([x, y, w, h, data], componentId, callback)
    },

    toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
        GCanvasModule.toTempFilePath([x, y, width, height, destWidth, destHeight, fileType, quality], componentId, callback)
    },
}

export default GBridge
